chibi.js ➔ chibi   F
last analyzed

Complexity

Conditions 130

Size

Total Lines 485
Code Lines 287

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 130
eloc 287
dl 0
loc 485
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like chibi.js ➔ chibi often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/*!chibi 3.0.9, Copyright 2012-2017 Kyle Barrow, released under MIT license */
2
(function () {
3
    'use strict';
4
5
    let readyfn = [],
6
        loadedfn = [],
7
        domready = false,
8
        pageloaded = false,
9
        jsonpcount = 0,
10
        d = document,
11
        w = window;
12
13
    // Fire any function calls on ready event
14
    function fireReady() {
15
        domready = true;
16
        readyfn.forEach(func => func());
17
        readyfn = [];
18
    }
19
20
    // Fire any function calls on loaded event
21
    function fireLoaded() {
22
        pageloaded = true;
23
        // For browsers with no DOM loaded support
24
        if (!domready) {
25
            fireReady();
26
        }
27
        loadedfn.forEach(func => func());
28
        loadedfn = [];
29
    }
30
31
    // Check DOM ready, page loaded
32
    if (d.addEventListener) {
33
        // Standards
34
        d.addEventListener('DOMContentLoaded', fireReady, false);
35
        w.addEventListener('load', fireLoaded, false);
36
    } else if (d.attachEvent) {
37
        // IE
38
        d.attachEvent('onreadystatechange', fireReady);
39
        // IE < 9
40
        w.attachEvent('onload', fireLoaded);
41
    } else {
42
        // Anything else
43
        w.onload = fireLoaded;
44
    }
45
46
    // Utility functions
47
48
    // Loop through node array
49
    function nodeLoop(fn, nodes) {
50
        let i;
51
        // Good idea to walk up the DOM
52
        for (i = nodes.length - 1; i >= 0; i -= 1) {
53
            fn(nodes[i]);
54
        }
55
    }
56
57
    // Convert to camel case
58
    function cssCamel(property) {
59
        return property.replace(/-\w/g, function (result) {return result.charAt(1).toUpperCase(); });
60
    }
61
62
    // Get computed style
63
    function computeStyle(elm, property) {
64
        // IE, everything else or null
65
        return (elm.currentStyle) ? elm.currentStyle[cssCamel(property)] : (w.getComputedStyle) ? w.getComputedStyle(elm, null).getPropertyValue(property) : null;
66
67
    }
68
69
    // Returns URI encoded query string pair
70
    function queryPair(name, value) {
71
        return encodeURIComponent(name).replace(/%20/g, '+') + '=' + encodeURIComponent(value).replace(/%20/g, '+');
72
    }
73
74
    // Set CSS, important to wrap in try to prevent error thrown on unsupported property
75
    function setCss(elm, property, value) {
76
        try {
77
            elm.style[cssCamel(property)] = value;
78
        } catch (e) {
79
            console.error('Could not set css style property "' + property + '".');
80
        }
81
    }
82
83
    // Show CSS
84
    function showCss(elm) {
85
        elm.style.display = '';
86
        // For elements still hidden by style block
87
        if (computeStyle(elm, 'display') === 'none') {
88
            elm.style.display = 'block';
89
        }
90
    }
91
92
    // Serialize form & JSON values
93
    function serializeData(nodes) {
94
        let querystring = '', subelm, i, j;
95
        if (nodes.constructor === Object) { // Serialize JSON data
96
            for (subelm in nodes) {
97
                if (nodes.hasOwnProperty(subelm)) {
98
                    if (nodes[subelm].constructor === Array) {
99
                        for (i = 0; i < nodes[subelm].length; i += 1) {
100
                            querystring += '&' + queryPair(subelm, nodes[subelm][i]);
101
                        }
102
                    } else {
103
                        querystring += '&' + queryPair(subelm, nodes[subelm]);
104
                    }
105
                }
106
            }
107
        } else { // Serialize node data
108
            nodeLoop(function (elm) {
109
                if (elm.nodeName === 'FORM') {
110
                    for (i = 0; i < elm.elements.length; i += 1) {
0 ignored issues
show
Bug introduced by
The variable i is changed as part of the for loop for example by 1 on line 110. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
111
                        subelm = elm.elements[i];
112
113
                        if (!subelm.disabled) {
0 ignored issues
show
Bug introduced by
The variable subelm is changed as part of the for loop for example by elm.elements.i on line 111. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
114
                            switch (subelm.type) {
115
                            // Ignore buttons, unsupported XHR 1 form fields
116
                            case 'button':
117
                            case 'image':
118
                            case 'file':
119
                            case 'submit':
120
                            case 'reset':
121
                                break;
122
123
                            case 'select-one':
124
                                if (subelm.length > 0) {
125
                                    querystring += '&' + queryPair(subelm.name, subelm.value);
0 ignored issues
show
Bug introduced by
The variable querystring is changed as part of the for loop for example by "&" + queryPair(subelm.name, subelm.value) on line 125. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
126
                                }
127
                                break;
128
129
                            case 'select-multiple':
130
                                for (j = 0; j < subelm.length; j += 1) {
0 ignored issues
show
Bug introduced by
The variable j is changed as part of the for loop for example by 1 on line 130. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
131
                                    if (subelm[j].selected) {
132
                                        querystring += '&' + queryPair(subelm.name, subelm[j].value);
133
                                    }
134
                                }
135
                                break;
136
137
                            case 'checkbox':
138
                            case 'radio':
139
                                if (subelm.checked) {
140
                                    querystring += '&' + queryPair(subelm.name, subelm.value);
141
                                }
142
                                break;
143
144
                            // Everything else including shinny new HTML5 input types
145
                            default:
146
                                querystring += '&' + queryPair(subelm.name, subelm.value);
147
                            }
148
                        }
149
                    }
150
                }
151
            }, nodes);
152
        }
153
        // Tidy up first &
154
        return (querystring.length > 0) ? querystring.substring(1) : '';
155
    }
156
157
    // Class helper
158
    function classHelper(classes, action, nodes) {
159
        let classarray, search, replace, i, has = false;
160
        if (classes) {
161
            // Trim any whitespace
162
            classarray = classes.split(/\s+/);
163
            nodeLoop(function (elm) {
164
                for (i = 0; i < classarray.length; i += 1) {
0 ignored issues
show
Bug introduced by
The variable i is changed as part of the for loop for example by 1 on line 164. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
165
                    search = new RegExp('\\b' + classarray[i] + '\\b', 'g');
166
                    replace = new RegExp(' *' + classarray[i] + '\\b', 'g');
167
                    if (action === 'remove') {
168
                        elm.className = elm.className.replace(replace, '');
0 ignored issues
show
Bug introduced by
The variable replace is changed as part of the for loop for example by new RegExp(" *" + classarray.i + "\\b", "g") on line 166. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
169
                    } else if (action === 'toggle') {
170
                        elm.className = (elm.className.match(search)) ? elm.className.replace(replace, '') : elm.className + ' ' + classarray[i];
0 ignored issues
show
Bug introduced by
The variable search is changed as part of the for loop for example by new RegExp("\\b" + classarray.i + "\\b", "g") on line 165. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
171
                    } else if (action === 'has') {
172
                        if (elm.className.match(search)) {
173
                            has = true;
174
                            break;
175
                        }
176
                    }
177
                }
178
            }, nodes);
179
        }
180
        return has;
181
    }
182
183
    // HTML insertion helper
184
    function insertHtml(value, position, nodes) {
185
        let tmpnodes, tmpnode;
186
        if (value) {
187
            nodeLoop(function (elm) {
188
                // No insertAdjacentHTML support for FF < 8 and IE doesn't allow insertAdjacentHTML table manipulation, so use this instead
189
                // Convert string to node. We can't innerHTML on a document fragment
190
                tmpnodes = d.createElement('div');
191
                tmpnodes.innerHTML = value;
192
                while ((tmpnode = tmpnodes.lastChild) !== null) {
193
                    // Catch error in unlikely case elm has been removed
194
                    try {
195
                        if (position === 'before') {
196
                            elm.parentNode.insertBefore(tmpnode, elm);
0 ignored issues
show
Bug introduced by
The variable tmpnode is changed as part of the while loop for example by tmpnodes.lastChild on line 192. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
197
                        } else if (position === 'after') {
198
                            elm.parentNode.insertBefore(tmpnode, elm.nextSibling);
199
                        } else if (position === 'append') {
200
                            elm.appendChild(tmpnode);
201
                        } else if (position === 'prepend') {
202
                            elm.insertBefore(tmpnode, elm.firstChild);
203
                        }
204
                    } catch (e) {break; }
205
                }
206
            }, nodes);
207
        }
208
    }
209
210
    // Get nodes and return chibi
211
    function chibi(selector) {
212
        let cb, nodes = [], json = false, nodelist, i;
213
214
        if (selector) {
215
216
            // Element node, would prefer to use (selector instanceof HTMLElement) but no IE support
217
            if (selector.nodeType && selector.nodeType === 1) {
218
                nodes = [selector]; // return element as node list
219
            } else if (typeof selector === 'object') {
220
                // JSON, document object or node list, would prefer to use (selector instanceof NodeList) but no IE support
221
                json = (typeof selector.length !== 'number');
222
                nodes = selector;
223
            } else if (typeof selector === 'string') {
224
225
                // A very light querySelectorAll polyfill for IE < 8. It suits my needs but is restricted to IE CSS support, is no speed demon, and does leave older mobile browsers in the cold (that support neither querySelectorAll nor currentStyle/getComputedStyle). If you want to use a fuller featured selector engine like Qwery, Sizzle et al, just return results to the nodes array: nodes = altselectorengine(selector)
226
227
                // IE < 8
228
                if (!d.querySelectorAll) {
229
                    // Polyfill querySelectorAll
230
                    d.querySelectorAll = function (selector) {
231
232
                        let style, head = d.getElementsByTagName('head')[0], allnodes, selectednodes = [], i;
233
234
                        style = d.createElement('STYLE');
235
                        style.type = 'text/css';
236
237
                        if (style.styleSheet) {
238
                            style.styleSheet.cssText = selector + ' {a:b}';
239
240
                            head.appendChild(style);
241
242
                            allnodes = d.getElementsByTagName('*');
243
244
                            for (i = 0; i < allnodes.length; i += 1) {
245
                                if (computeStyle(allnodes[i], 'a') === 'b') {
246
                                    selectednodes.push(allnodes[i]);
247
                                }
248
                            }
249
250
                            head.removeChild(style);
251
                        }
252
253
                        return selectednodes;
254
                    };
255
                }
256
257
                nodelist = d.querySelectorAll(selector);
258
259
                // Convert node list to array so results have full access to array methods
260
                // Array.prototype.slice.call not supported in IE < 9 and often slower than loop anyway
261
                for (i = 0; i < nodelist.length; i += 1) {
262
                    nodes[i] = nodelist[i];
263
                }
264
265
            }
266
        }
267
268
        // Only attach nodes if not JSON
269
        cb = json ? {} : nodes;
270
271
        // Public functions
272
273
        // Fire on DOM ready
274
        cb.ready = function (fn) {
275
            if (fn) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if fn is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
276
                if (domready) {
277
                    fn();
278
                    return cb;
279
                } else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
280
                    readyfn.push(fn);
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
281
                }
282
            }
283
        };
284
        // Fire on page loaded
285
        cb.loaded = function (fn) {
286
            if (fn) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if fn is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
287
                if (pageloaded) {
288
                    fn();
289
                    return cb;
290
                } else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
291
                    loadedfn.push(fn);
0 ignored issues
show
Best Practice introduced by
There is no return statement in this branch, but you do return something in other branches. Did you maybe miss it? If you do not want to return anything, consider adding return undefined; explicitly.
Loading history...
292
                }
293
            }
294
        };
295
        // Executes a function on nodes
296
        cb.each = function (fn) {
297
            if (typeof fn === 'function') {
298
                nodeLoop(function (elm) {
299
                    // <= IE 8 loses scope so need to apply
300
                    return fn.apply(elm, arguments);
301
                }, nodes);
302
            }
303
            return cb;
304
        };
305
        // Find parent
306
        cb.parent = function () {
307
            return nodes.length > 0 ? chibi(nodes[0].parentNode) : null;
308
        };
309
        // Find first
310
        cb.first = function () {
311
            return chibi(nodes.shift());
312
        };
313
        // Find last
314
        cb.last = function () {
315
            return chibi(nodes.pop());
316
        };
317
        // Find odd
318
        cb.odd = function () {
319
            let odds = [], i;
320
            for (i = 0; i < nodes.length; i += 2) {
321
                odds.push(nodes[i]);
322
            }
323
            return chibi(odds);
324
        };
325
        // Find even
326
        cb.even = function () {
327
            let evens = [], i;
328
            for (i = 1; i < nodes.length; i += 2) {
329
                evens.push(nodes[i]);
330
            }
331
            return chibi(evens);
332
        };
333
        // Hide node
334
        cb.hide = function () {
335
            nodeLoop(function (elm) {
336
                elm.style.display = 'none';
337
            }, nodes);
338
            return cb;
339
        };
340
        // Show node
341
        cb.show = function () {
342
            nodeLoop(function (elm) {
343
                showCss(elm);
344
            }, nodes);
345
            return cb;
346
        };
347
        // Toggle node display
348
        cb.toggle = function () {
349
            nodeLoop(function (elm) {
350
                // computeStyle instead of style.display == 'none' catches elements that are hidden via style block
351
                if (computeStyle(elm, 'display') === 'none') {
352
                    showCss(elm);
353
                } else {
354
                    elm.style.display = 'none';
355
                }
356
357
            }, nodes);
358
            return cb;
359
        };
360
        // Remove node
361
        cb.remove = function () {
362
            nodeLoop(function (elm) {
363
                // Catch error in unlikely case elm has been removed
364
                try {
365
                    elm.parentNode.removeChild(elm);
366
                } catch (e) {}
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
367
            }, nodes);
368
            return chibi();
369
        };
370
        // Get/Set CSS
371
        cb.css = function (property, value) {
372
            if (property) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if property is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
373
                if (value || value === '') {
374
                    nodeLoop(function (elm) {
375
                        setCss(elm, property, value);
376
                    }, nodes);
377
                    return cb;
378
                }
379
                if (nodes[0]) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if nodes.0 is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
380
                    if (nodes[0].style[cssCamel(property)]) {
381
                        return nodes[0].style[cssCamel(property)];
382
                    }
383
                    if (computeStyle(nodes[0], property)) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if computeStyle(nodes.0, property) is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
384
                        return computeStyle(nodes[0], property);
385
                    }
386
                }
387
            }
388
        };
389
        // Get class(es)
390
        cb.getClass = function () {
391
            if (nodes[0] && nodes[0].className.length > 0) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if nodes.0 && nodes.0.className.length > 0 is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
392
                // Weak IE trim support
393
                return nodes[0].className.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '').replace(/\s+/,' ');
394
            }
395
        };
396
        // Set (replaces) classes
397
        cb.setClass = function (classes) {
398
            if (classes || classes === '') {
399
                nodeLoop(function (elm) {
400
                    elm.className = classes;
401
                }, nodes);
402
            }
403
            return cb;
404
        };
405
        // Add class
406
        cb.addClass = function (classes) {
407
            if (classes) {
408
                nodeLoop(function (elm) {
409
                    elm.className += ' ' + classes;
410
                }, nodes);
411
            }
412
            return cb;
413
        };
414
        // Remove class
415
        cb.removeClass = function (classes) {
416
            classHelper(classes, 'remove', nodes);
417
            return cb;
418
        };
419
        // Toggle class
420
        cb.toggleClass = function (classes) {
421
            classHelper(classes, 'toggle', nodes);
422
            return cb;
423
        };
424
        // Has class
425
        cb.hasClass = function (classes) {
426
            return classHelper(classes, 'has', nodes);
427
        };
428
        // Get/set HTML
429
        cb.html = function (value) {
430
            if (value || value === '') {
431
                nodeLoop(function (elm) {
432
                    elm.innerHTML = value;
433
                }, nodes);
434
                return cb;
435
            }
436
            if (nodes[0]) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if nodes.0 is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
437
                return nodes[0].innerHTML;
438
            }
439
        };
440
        // Insert HTML before selector
441
        cb.htmlBefore = function (value) {
442
            insertHtml(value, 'before', nodes);
443
            return cb;
444
        };
445
        // Insert HTML after selector
446
        cb.htmlAfter = function (value) {
447
            insertHtml(value, 'after', nodes);
448
            return cb;
449
        };
450
        // Insert HTML after selector innerHTML
451
        cb.htmlAppend = function (value) {
452
            insertHtml(value, 'append', nodes);
453
            return cb;
454
        };
455
        // Insert HTML before selector innerHTML
456
        cb.htmlPrepend = function (value) {
457
            insertHtml(value, 'prepend', nodes);
458
            return cb;
459
        };
460
        // Get/Set HTML attributes
461
        cb.attr = function (property, value) {
462
            if (property) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if property is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
463
                property = property.toLowerCase();
464
                // IE < 9 doesn't allow style or class via get/setAttribute so switch. cssText returns prettier CSS anyway
465
                if (value || value === '') {
466
                    nodeLoop(function (elm) {
467
                        if (property === 'style') {
468
                            elm.style.cssText = value;
469
                        } else if (property === 'class') {
470
                            elm.className = value;
471
                        } else {
472
                            elm.setAttribute(property, value);
473
                        }
474
                    }, nodes);
475
                    return cb;
476
                }
477
                if (nodes[0]) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if nodes.0 is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
478
                    if (property === 'style') {
479
                        if (nodes[0].style.cssText) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if nodes.0.style.cssText is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
480
                            return nodes[0].style.cssText;
481
                        }
482
                    } else if (property === 'class') {
483
                        if (nodes[0].className) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if nodes.0.className is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
484
                            return nodes[0].className;
485
                        }
486
                    } else {
487
                        if (nodes[0].getAttribute(property)) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if nodes.0.getAttribute(property) is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
488
                            return nodes[0].getAttribute(property);
489
                        }
490
                    }
491
                }
492
            }
493
        };
494
        // Get/Set HTML data property
495
        cb.data = function (key, value) {
496
            if (key) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if key is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
497
                return cb.attr('data-'+key, value);
498
            }
499
        };
500
        // Get/Set form element values
501
        cb.val = function (value) {
502
            let values, i, j;
503
            if (value || value === '') {
504
                nodeLoop(function (elm) {
505
                    switch (elm.nodeName) {
506
                    case 'SELECT':
507
                        if (typeof value === 'string' || typeof value === 'number') {
508
                            value = [value];
509
                        }
510
                        for (i = 0; i < elm.length; i += 1) {
0 ignored issues
show
Bug introduced by
The variable i is changed as part of the for loop for example by 1 on line 510. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
511
                            // Multiple select
512
                            for (j = 0; j < value.length; j += 1) {
0 ignored issues
show
Bug introduced by
The variable j is changed as part of the for loop for example by 1 on line 512. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
513
                                elm[i].selected = '';
514
                                if (elm[i].value === value[j]) {
515
                                    elm[i].selected = 'selected';
516
                                    break;
517
                                }
518
                            }
519
                        }
520
                        break;
521
                    case 'INPUT':
522
                    case 'TEXTAREA':
523
                    case 'BUTTON':
524
                        elm.value = value;
525
                        break;
526
                    }
527
                }, nodes);
528
529
                return cb;
530
            }
531
            if (nodes[0]) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if nodes.0 is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
532
                switch (nodes[0].nodeName) {
533
                case 'SELECT':
534
                    values = [];
535
                    for (i = 0; i < nodes[0].length; i += 1) {
536
                        if (nodes[0][i].selected) {
537
                            values.push(nodes[0][i].value);
538
                        }
539
                    }
540
                    return (values.length > 1) ? values : values[0];
541
                case 'INPUT':
542
                case 'TEXTAREA':
543
                case 'BUTTON':
544
                    return nodes[0].value;
545
                }
0 ignored issues
show
Comprehensibility introduced by
There is no default case in this switch, so nothing gets returned when all cases fail. You might want to consider adding a default or return undefined explicitly.
Loading history...
546
            }
547
        };
548
        // Return matching checked checkbox or radios
549
        cb.checked = function (check) {
550
            if (typeof check === 'boolean') {
551
                nodeLoop(function (elm) {
552
                    if (elm.nodeName === 'INPUT' && (elm.type === 'checkbox' || elm.type === 'radio')) {
553
                        elm.checked = check;
554
                    }
555
                }, nodes);
556
                return cb;
557
            }
558
            if (nodes[0] && nodes[0].nodeName === 'INPUT' && (nodes[0].type === 'checkbox' || nodes[0].type === 'radio')) {
0 ignored issues
show
Complexity Best Practice introduced by
There is no return statement if nodes.0 && nodes.0.nodeN...odes.0.type === "radio" is false. Are you sure this is correct? If so, consider adding return; explicitly.

This check looks for functions where a return statement is found in some execution paths, but not in all.

Consider this little piece of code

function isBig(a) {
    if (a > 5000) {
        return "yes";
    }
}

console.log(isBig(5001)); //returns yes
console.log(isBig(42)); //returns undefined

The function isBig will only return a specific value when its parameter is bigger than 5000. In any other case, it will implicitly return undefined.

This behaviour may not be what you had intended. In any case, you can add a return undefined to the other execution path to make the return value explicit.

Loading history...
559
                return (!!nodes[0].checked);
560
            }
561
        };
562
        // Add event handler
563
        cb.on = function (event, fn) {
564
            if (selector === w || selector === d) {
565
                nodes = [selector];
566
            }
567
            nodeLoop(function (elm) {
568
                if (d.addEventListener) {
569
                    elm.addEventListener(event, fn, false);
570
                } else if (d.attachEvent) {
571
                    // <= IE 8 loses scope so need to apply, we add this to object so we can detach later (can't detach anonymous functions)
572
                    elm[event + fn] =  function () { return fn.apply(elm, arguments); };
573
                    elm.attachEvent('on' + event, elm[event + fn]);
574
                }
575
            }, nodes);
576
            return cb;
577
        };
578
        // Remove event handler
579
        cb.off = function (event, fn) {
580
            if (selector === w || selector === d) {
581
                nodes = [selector];
582
            }
583
            nodeLoop(function (elm) {
584
                if (d.addEventListener) {
585
                    elm.removeEventListener(event, fn, false);
586
                } else if (d.attachEvent) {
587
                    elm.detachEvent('on' + event, elm[event + fn]);
588
                    // Tidy up
589
                    elm[event + fn] = null;
590
                }
591
            }, nodes);
592
            return cb;
593
        };
594
        // Basic XHR 1, no file support. Shakes fist at IE
595
        cb.ajax = function (url, method, callback, nocache, nojsonp) {
596
            let xhr,
597
                query = serializeData(nodes),
598
                type = (method) ? method.toUpperCase() : 'GET',
599
                hostsearch = new RegExp('http[s]?://(.*?)/', 'gi'),
600
                domain = hostsearch.exec(url),
601
                timestamp = '_ts=' + (+new Date()),
602
                head = d.getElementsByTagName('head')[0],
603
                jsonpcallback = 'chibi' + (+new Date()) + (jsonpcount += 1),
604
                script;
605
606
            if (query && (type === 'GET' || type === 'DELETE')) {
607
                url += (url.indexOf('?') === -1) ? '?' + query : '&' + query;
608
                query = null;
609
            }
610
611
            // JSONP if cross domain url
612
            if (type === 'GET' && !nojsonp && domain && w.location.host !== domain[1]) {
613
614
                if (nocache) {
615
                    url += (url.indexOf('?') === -1) ? '?' + timestamp : '&' + timestamp;
616
                }
617
618
                // Replace possible encoded ?
619
                url = url.replace('=%3F', '=?');
620
621
                // Replace jsonp ? with callback
622
                if (callback && url.indexOf('=?') !== -1) {
623
624
                    url = url.replace('=?', '=' + jsonpcallback);
625
626
                    w[jsonpcallback] = function (data) {
627
                        try {
628
                            callback(data, 200);
629
                        } catch (e) {}
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
630
631
                        // Tidy up
632
                        w[jsonpcallback] = undefined;
633
                    };
634
                }
635
636
                // JSONP
637
                script = document.createElement('script');
638
                script.async = true;
639
                script.src = url;
640
641
                // Tidy up
642
                script.onload = function () {
643
                    head.removeChild(script);
644
                };
645
646
                head.appendChild(script);
647
648
            } else {
649
650
                if (w.XMLHttpRequest) {
651
                    xhr = new XMLHttpRequest();
652
                } else if (w.ActiveXObject) {
653
                    xhr = new ActiveXObject('Microsoft.XMLHTTP'); // IE < 9
0 ignored issues
show
Bug introduced by
The variable ActiveXObject seems to be never declared. If this is a global, consider adding a /** global: ActiveXObject */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
654
                }
655
656
                if (xhr) {
657
658
                    if (nocache) {
659
                        url += (url.indexOf('?') === -1) ? '?' + timestamp : '&' + timestamp;
660
                    }
661
662
                    // Douglas Crockford: "Synchronous programming is disrespectful and should not be employed in applications which are used by people"
663
                    xhr.open(type, url, true);
664
665
                    xhr.onreadystatechange = function () {
666
                        if (xhr.readyState === 4) {
667
                            if (callback) {
668
                                callback(xhr.responseText, xhr.status);
669
                            }
670
                        }
671
                    };
672
673
                    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
674
675
                    if (type === 'POST' || type === 'PUT') {
676
                        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
677
                    }
678
679
                    xhr.send(query);
680
681
                }
682
            }
683
            return cb;
684
        };
685
        // Alias to cb.ajax(url, 'get', callback, nocache, nojsonp)
686
        cb.get = function (url, callback, nocache, nojsonp) {
687
            return cb.ajax(url, 'get', callback, nocache, nojsonp);
688
        };
689
        // Alias to cb.ajax(url, 'post', callback, nocache)
690
        cb.post = function (url, callback, nocache) {
691
            return cb.ajax(url, 'post', callback, nocache);
692
        };
693
694
        return cb;
695
    }
696
697
    // Set Chibi's global namespace here (chibi)
698
    w.chibi = chibi;
699
700
}());
701